import { Element, PaintContext, PrepaintState } from './element'
import { App, WindowInvalidator } from './app'
import { EntityId } from './entity_map'
import { Scene } from './scene'
import { createDefaultPaintContext } from './paint_context'

/**
 * 视图缓存键，用于确定视图是否需要重新渲染
 */
export class ViewCacheKey {
  bounds?: { x: number; y: number; width: number; height: number }
  contentMask?: any
  textStyle?: any

  constructor(options: Partial<ViewCacheKey> = {}) {
    this.bounds = options.bounds
    this.contentMask = options.contentMask
    this.textStyle = options.textStyle
  }

  equals(other: ViewCacheKey): boolean {
    return (
      JSON.stringify(this.bounds) === JSON.stringify(other.bounds) &&
      JSON.stringify(this.contentMask) === JSON.stringify(other.contentMask) &&
      JSON.stringify(this.textStyle) === JSON.stringify(other.textStyle)
    )
  }
}

/**
 * 视图状态，用于存储视图的缓存信息
 */
export class ViewState {
  prepaintState: any
  paintState: any
  cacheKey: ViewCacheKey
  accessedEntities: Set<EntityId>
  isDirty: boolean

  constructor() {
    this.prepaintState = null
    this.paintState = null
    this.cacheKey = new ViewCacheKey()
    this.accessedEntities = new Set()
    this.isDirty = true
  }
}

/**
 * 窗口ID生成器
 */
class WindowIdGenerator {
  private static nextId = 1
  static generate(): number {
    return this.nextId++
  }
}

/**
 * 窗口无效器实现
 */
class WindowInvalidatorImpl implements WindowInvalidator {
  private window: Window

  constructor(window: Window) {
    this.window = window
  }

  invalidate_view(entityId: EntityId, _app: App): void {
    // 标记相关视图为脏状态
    this.window.markViewAsDirty(entityId)
    console.debug(`Invalidating view for entity ${entityId}`)
  }
}

/**
 * 窗口类，管理元素的布局和渲染
 */
export class Window {
  private app: App
  private id: number
  private invalidator: WindowInvalidator
  private size = {
    width: 0,
    height: 0
  }
  private rootElement: Element | null = null
  private scene: Scene
  private renderedFrame: {
    scene: Scene
  } | null = null
  
  // 增量渲染相关属性
  private dirtyViews: Set<EntityId> = new Set()
  private viewStates: Map<string, ViewState> = new Map()
  private refreshing: boolean = false
  private currentViewId: EntityId | null = null

  constructor(app: App) {
    this.app = app
    this.id = WindowIdGenerator.generate()
    this.invalidator = new WindowInvalidatorImpl(this)
    this.scene = new Scene()
    this.dirtyViews = new Set()
    this.viewStates = new Map()
  }

  /**
   * 获取窗口ID
   */
  getId(): number {
    return this.id
  }

  /**
   * 设置根元素
   */
  setRootElement(element: Element): void {
    this.rootElement = element
  }

  /**
   * 获取根元素
   */
  getRootElement(): Element | null {
    return this.rootElement
  }

  /**
   * 绘制根元素到Scene
   */
  drawRoots(): void {
    if (!this.rootElement) return

    // 检查是否需要完全重新创建Scene
    const needsFullRecreate = this.refreshing || this.dirtyViews.size === 0
    
    if (needsFullRecreate) {
      // 创建新的Scene
      this.scene.clear()
    }

    // 检测访问的实体
    const accessedEntities = new Set<EntityId>()
    const detectAccessed = (callback: () => void) => {
      // 实际应用中，这里应该实现更复杂的实体访问检测逻辑
      callback()
      return accessedEntities
    }

    // 预绘制阶段
    const prepaintState: PrepaintState = {
      parentTransform: { x: 0, y: 0 },
      opacity: 1
    }
    
    // 预绘制并收集访问的实体
    const prepaintedAccessedEntities = detectAccessed(() => {
      this.rootElement!.prepaint(prepaintState)
    })
    
    // 合并访问的实体
    prepaintedAccessedEntities.forEach(entityId => accessedEntities.add(entityId))

    // 绘制阶段
    const paintContext: PaintContext = createDefaultPaintContext(this.scene, needsFullRecreate)
    
    // 绘制并收集访问的实体
    const paintedAccessedEntities = detectAccessed(() => {
      this.rootElement!.paint(paintContext)
    })
    
    // 合并访问的实体
    paintedAccessedEntities.forEach(entityId => accessedEntities.add(entityId))

    // 完成Scene构建
    this.scene.finish()

    // 保存渲染结果
    this.renderedFrame = { scene: this.scene }

    // 记录窗口访问的实体
    this.app.recordEntitiesAccessed(this.id, this.invalidator, accessedEntities)

    // 重置脏标记
    this.dirtyViews.clear()
    this.refreshing = false
  }
  
  /**
   * 标记视图为脏状态
   */
  markViewAsDirty(entityId: EntityId): void {
    this.dirtyViews.add(entityId)
    this.invalidate()
  }
  
  /**
   * 设置当前正在处理的视图ID
   */
  setViewId(entityId: EntityId): void {
    this.currentViewId = entityId
  }
  
  /**
   * 获取当前正在处理的视图ID
   */
  getViewId(): EntityId | null {
    return this.currentViewId
  }
  
  /**
   * 获取内容掩码
   */
  contentMask(): any {
    // 实现内容掩码逻辑
    return null
  }
  
  /**
   * 获取文本样式
   */
  textStyle(): any {
    // 实现文本样式逻辑
    return null
  }
  
  /**
   * 检查视图是否脏
   */
  isViewDirty(entityId: EntityId): boolean {
    return this.dirtyViews.has(entityId)
  }
  
  /**
   * 刷新所有视图
   */
  refresh(): void {
    this.refreshing = true
    this.invalidate()
  }
  
  /**
   * 获取视图状态
   */
  getViewState(key: string): ViewState | undefined {
    return this.viewStates.get(key)
  }
  
  /**
   * 保存视图状态
   */
  saveViewState(key: string, state: ViewState): void {
    this.viewStates.set(key, state)
  }

  /**
   * 呈现场景到屏幕
   */
  present(): void {
    if (!this.renderedFrame) {
      this.drawRoots()
    }

    if (this.renderedFrame) {
      // 这里会在app.ts中调用实际的渲染逻辑
      this.app.render()
    }
  }

  /**
   * 获取当前场景
   */
  getScene(): Scene {
    return this.scene
  }

  /**
   * 获取渲染的帧
   */
  getRenderedFrame(): { scene: Scene } | null {
    return this.renderedFrame
  }

  /**
   * 设置窗口大小
   */
  setSize(width: number, height: number): void {
    this.size = {
      width,
      height
    }
  }

  /**
   * 获取窗口大小
   */
  getSize(): { width: number; height: number } {
    return this.size
  }

  /**
   * 获取应用实例
   */
  getApp(): App {
    return this.app
  }

  /**
   * 获取窗口无效器
   */
  getInvalidator(): WindowInvalidator {
    return this.invalidator
  }

  /**
   * 触发窗口重绘
   */
  invalidate(): void {
    this.app.requestRender()
  }
}